namespace Math
{
    const double PI = 3.1415926535897932384626433832795028842;
    const float PIf = 3.14159265358979323846f;

    //
    // rnd() returns a number between 0.0 and 1.0
    //
    #define rnd()            (((float)rand() ) / RAND_MAX)

    //
    // pmrnd() returns a number between -1.0 and 1.0
    //
    #define pmrnd()            ((rnd() - 0.5f) * 2.0f)

    inline float DegreesToRadians(float x)
    {
        return x * PIf / 180.0f;
    }

    inline float RadiansToDegrees(float x)
    {
        return x * 180.0f / PIf;
    }

	template <class T>
	inline T StandardizeAngle(T rads)
	{
		T TWOPI = (T)(2.0*Math::PI);
		while (rads < 0.0f) rads += TWOPI;
		while (rads > TWOPI) rads -= TWOPI;
		return rads;
	}

    inline float Sign(float x)
    {
        if(x < 0.0f)
        {
            return -1.0f;
        }
        else
        {
            return 1.0f;
        }
    }
    
    template <class type> inline type Bound(type Value, type Low, type High)
    {
        if(Value < Low)
        {
            Value = Low;
        }
        if(Value > High)
        {
            Value = High;
        }
        return Value;
    }

    inline double Sigmoid(double X)
    {
        return 1.0 / (1.0 + exp(-X));
    }
    
    inline float LinearMap(float s1, float e1, float s2, float e2, float start)
    {
        return ((start-s1)*(e2-s2)/(e1-s1)+s2);
    }

    inline double LinearMap(double s1, double e1, double s2, double e2, double start)
    {
        return ((start-s1)*(e2-s2)/(e1-s1)+s2);
    }

    inline long double LinearMap(long double s1, long double e1, long double s2, long double e2, long double start)
    {
        return ((start-s1)*(e2-s2)/(e1-s1)+s2);
    }

    inline float Lerp(float left, float right, float s)
    {
        return (left + s * (right - left));
    }

    inline double Lerp(double left, double right, double s)
    {
        return (left + s * (right - left));
    }

    inline long double Lerp(long double left, long double right, long double s)
    {
        return (left + s * (right - left));
    }

    inline int AbsInt(int x)
    {
        if(x < 0)
        {
            return -x;
        }
        else
        {
            return x;
        }
    }

    inline int Mod(int x, unsigned int M)
    {
        if(x >= 0)
        {
            return (x % M);
        }
        else
        {
            return ((x + (x / int(M) + 2) * int(M)) % M);
        }
    }

    inline int Floor(float x)
    {
        if(x >= 0.0f)
        {
            return int(x);
        }
        else
        {
            return int(x) - 1;
        }
    }

    inline int Floor(double x)
    {
        if(x >= 0.0)
        {
            return int(x);
        }
        else
        {
            return int(x) - 1;
        }
    }

    inline int Ceiling(float x)
    {
        int FloorX = Floor(x);
        if(x == float(FloorX))
        {
            return FloorX;
        }
        else
        {
            return FloorX + 1;
        }
    }

    inline int Ceiling(double x)
    {
        int FloorX = Floor(x);
        if(x == double(FloorX))
        {
            return FloorX;
        }
        else
        {
            return FloorX + 1;
        }
    }

    inline int Round(float x)
    {
        return int(x + 0.5f);
    }

    inline int Round(double x)
    {
        return int(x + 0.5);
    }

    template <class type> inline type Square(type T)
    {
        return T * T;
    }

    template <class type> inline type Min(type A, type B)
    {
        if(A < B)
        {
            return A;
        }
        else
        {
            return B;
        }
    }

    template <class type> inline type Min(type A, type B, type C)
    {
        if(A < B && A < C)
        {
            return A;
        }
        else if(B < C)
        {
            return B;
        }
        else
        {
            return C;
        }
    }

    template <class type> inline type Max(type A, type B)
    {
        if(A > B)
        {
            return A;
        }
        else
        {
            return B;
        }
    }

    template <class type> inline type Max(type A, type B, type C)
    {
        if(A > B && A > C)
        {
            return A;
        }
        else if(B > C)
        {
            return B;
        }
        else
        {
            return C;
        }
    }

} // end Math namespace
